package cur.nature.framework.core.log;

import ch.qos.logback.classic.pattern.LineOfCallerConverter;
import ch.qos.logback.classic.spi.CallerData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;

/**
 * @author wujian
 * @Date 2018-07-16
 */
public class LineNumberConverter extends LineOfCallerConverter {

    private static final String FQCN = LOG.class.getName();

    @Override
    public String convert(ILoggingEvent le) {
//        StackTraceElement[] cda = getCallerData((LoggingEvent) le);
//        if (cda != null && cda.length > 0) {
//            if(FQCN.equals(cda[0].getClassName())){
//                return cda[1].getLineNumber()+"";
//            }else {return cda[0].getLineNumber()+"";}
//        } else {
//            return super.convert(le);
//        }
        StackTraceElement cda = getCallerData((LoggingEvent) le);
        if (cda != null) { return cda.getLineNumber()+"";
        } else { return super.convert(le); }
    }

//    private StackTraceElement getTraceElement(String class1, LoggingEvent le) {
//        StackTraceElement[] steArray = null;
//        if(le.hasCallerData()){steArray = le.getCallerData();}
//        else {steArray = new Throwable().getStackTrace();le.setCallerData(steArray);}
//        StackTraceElement res = null;
//        int i;
//        for (i=0;i<steArray.length;i++) {
//            if (class1.equals(steArray[i].getClassName())) { break;}
//        }
//
//        return steArray[i+1];
//    }
//    private boolean checkIsService(String class1, String class2) {
//        StackTraceElement[] steArray = new Throwable().getStackTrace();
//        // check if LogService or LogUtil
//        for (StackTraceElement aSteArray : steArray) {
//            if (class1.equals(aSteArray.getClassName())
//                    || class2.equals(aSteArray.getClassName())) {
//                return true;
//            }
//        }
//        return false;
//    }
//
    private StackTraceElement getCallerData(LoggingEvent event) {
        StackTraceElement[] array = null;
        StackTraceElement res = null;
        if (event.hasCallerData()) {
//            array = (StackTraceElement[]) Arrays.asList(getTraceElement(FQCN,event.getCallerData())).toArray();
            array = event.getCallerData();

        }else{
//            array = extract(new Throwable(), FQCN, ClassicConstants.DEFAULT_MAX_CALLEDER_DATA_DEPTH);
//            if(FQCN.equals(array[0].getClassName())){
//                res = array[1];
//            }else {
//                res = array[0];
//            }
            array = (new Throwable()).getStackTrace();
        }


        res = getTraceElement(array);

        return res;
    }

    private StackTraceElement[] extract(Throwable t, String fqnOfInvokingClass, final int maxDepth) {

        StackTraceElement[] steArray = t.getStackTrace();
        StackTraceElement[] callerDataArray;

        int found = CallerData.LINE_NA;
        for (int i = 0; i < steArray.length; i++) {
            if (fqnOfInvokingClass.equals(steArray[i].getClassName())) {
                found = i + 1;
            } else { if (found != CallerData.LINE_NA) { break;}}
        }

        if (found == CallerData.LINE_NA) {
            return CallerData.EMPTY_CALLER_DATA_ARRAY;
        }

        int availableDepth = steArray.length - found;
        int desiredDepth = maxDepth < (availableDepth) ? maxDepth : availableDepth;

        callerDataArray = new StackTraceElement[desiredDepth];
        for (int i = 0; i < desiredDepth; i++) {callerDataArray[i] = steArray[found + i];}
        return callerDataArray;
    }

    private StackTraceElement getTraceElement(StackTraceElement[] steArray) {
        StackTraceElement res = null;
        for (int i=0;i<steArray.length;i++) {
            if (FQCN.equals(steArray[i].getClassName())) { res = steArray[i+1];break;}
        }
        return res;
    }
}
